#include "StdAfx.h"
#include "RenderableObject.h"
#include "ViewFrustrum.h"
#include "IMovable.h"
#include "BoundingVolume.h"
#include "IMesh.h"


///////////////////////////////////////////////////////////////////////////////

CRenderableObject::CRenderableObject(IMesh& mesh, const D3DMATERIAL9& material)
      : m_rightVec(1, 0, 0),
      m_upVec(0, 1, 0),
      m_lookVec(0, 0, 1),
      m_position(0, 0, 0),
      m_mesh(mesh),
      m_mtxWorldDirty(true),
      m_material(material)
{
   D3DXMatrixIdentity(&m_mtxWorld);
}

///////////////////////////////////////////////////////////////////////////////

void CRenderableObject::render(CViewFrustrum& frustrum, IDirect3DDevice9& d3Device)
{
   d3Device.SetMaterial(&m_material);
   d3Device.SetTransform(D3DTS_WORLD, &getMtxWorld());

   if (frustrum.isInside(getWorldSpaceBoundingBox()) == true)
   {
      m_mesh.render();
   }
}

///////////////////////////////////////////////////////////////////////////////

AABoundingBox CRenderableObject::getWorldSpaceBoundingBox() const
{
   AABoundingBox bbox = m_mesh.getModelSpaceBoundingBox();
   bbox.min += getPosition();
   bbox.max += getPosition();

   return bbox;
}

///////////////////////////////////////////////////////////////////////////////

const D3DXMATRIX& CRenderableObject::getMtxWorld()
{
   if (m_mtxWorldDirty)
   {
      D3DXMatrixIdentity(&m_mtxWorld);

      m_mtxWorld._11 = m_rightVec.x; m_mtxWorld._12 = m_rightVec.y; m_mtxWorld._13 = m_rightVec.z;
      m_mtxWorld._21 = m_upVec.x;    m_mtxWorld._22 = m_upVec.y;     m_mtxWorld._23 = m_upVec.z;
      m_mtxWorld._31 = m_lookVec.x;  m_mtxWorld._32 = m_lookVec.y;  m_mtxWorld._33 = m_lookVec.z;
      m_mtxWorld._41 = m_position.x; m_mtxWorld._42 = m_position.y; m_mtxWorld._43 = m_position.z;
   }

   return m_mtxWorld;
}

///////////////////////////////////////////////////////////////////////////////

void CRenderableObject::move(const D3DXVECTOR3& transVec)
{
   m_position += transVec;
   m_mtxWorldDirty = true;
}

///////////////////////////////////////////////////////////////////////////////

void CRenderableObject::rotate(float pitch, float yaw, float roll)
{
   if (pitch)
   {
      D3DXMATRIX mtxRotate;
      D3DXMatrixIdentity(&mtxRotate);
      D3DXMatrixRotationAxis(&mtxRotate, &m_rightVec, D3DXToRadian(pitch));

      D3DXVec3TransformNormal(&m_upVec, &m_upVec, &mtxRotate);
      D3DXVec3TransformNormal(&m_lookVec, &m_lookVec, &mtxRotate);
   }

   if (yaw)
   {
      D3DXMATRIX mtxRotate;
      D3DXMatrixIdentity(&mtxRotate);
      D3DXMatrixRotationAxis(&mtxRotate, &m_upVec, D3DXToRadian(yaw));

      D3DXVec3TransformNormal(&m_rightVec, &m_rightVec, &mtxRotate);
      D3DXVec3TransformNormal(&m_lookVec, &m_lookVec, &mtxRotate);
   }

   if (roll)
   {
      D3DXMATRIX mtxRotate;
      D3DXMatrixIdentity(&mtxRotate);
      D3DXMatrixRotationAxis(&mtxRotate, &m_lookVec, D3DXToRadian(roll));

      D3DXVec3TransformNormal(&m_rightVec, &m_rightVec, &mtxRotate);
      D3DXVec3TransformNormal(&m_upVec, &m_upVec, &mtxRotate);
   }

   // regenerate vectors
   D3DXVec3Normalize(&m_lookVec, &m_lookVec);
   D3DXVec3Cross(&m_rightVec, &m_upVec, &m_lookVec);
   D3DXVec3Normalize(&m_rightVec, &m_rightVec);
   D3DXVec3Cross(&m_upVec, &m_lookVec, &m_rightVec);
   D3DXVec3Normalize(&m_upVec, &m_upVec);
}

///////////////////////////////////////////////////////////////////////////////
